/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
 */
package td.server;

import java.util.Date;

import td.domain.Thinker;
import td.domain.Thought;
import td.domain.delta.VersionAdd;
import td.domain.delta.VersionPublish;
import td.domain.util.IdCache;
import td.server.dao.ObjectifyDao;
import td.server.dao.ThinkerDao;
import td.server.dao.ThoughtDao;
import td.server.dao.ThoughtVersionDao;
import td.server.util.Validator;
import td.server.util.Versioner;
import td.shared.InvalidStateException;

import com.google.inject.Inject;

/**
 * @author Artem Shamsutdinov
 * 
 */
public class VersionService {

	@Inject
	Validator validator;
	@Inject
	Versioner versioner;
	@Inject
	ThinkerDao thinkerDao;
	@Inject
	ThoughtDao thoughtDao;
	@Inject
	ThoughtVersionDao thoughtVersionDao;
	@Inject
	ObjectifyDao<VersionAdd> versionAddDao;
	@Inject
	ObjectifyDao<VersionPublish> versionPublishDao;
	@Inject
	ObjectifyDao<IdCache> idCacheDao;

	// TODO: add action that pre-loads published and unpublished thoughts
	// of the thinker ONLY IF "publish=true". AND add verification that
	// the passed in thinker is the owner of the thought being published

	/**
	 * A thinker can add a version to a given thought (of hers). This version
	 * can either be published or not-published. You can only add a published
	 * version once, after that no new versions can be added to that thought
	 * since it's published. Hence, if a published version is added to a
	 * previously unpublished thought then that thought becomes published.
	 * 
	 * @param thoughtId
	 *            Id of the thought to which a version is being added.
	 * @param text
	 *            Text of the new version
	 * @param thinker
	 *            Thinker to which the thought belongs to.
	 * @param publish
	 *            Should the new version be published?
	 * @return The thought to which the version was added
	 * @throws InvalidStateException
	 */
	public Thought addVersion(Thought thought, String text, Thinker thinker,
			boolean publish) throws InvalidStateException {
		return null;
		// FIXME: add this back in and figure out how to deal with Ref in GWT
		// // Not allowing (currently) to add new versions after a thought has
		// been
		// // published
		// validator.validateUnpublishedThought(thinker, thought);
		//
		// // When adding a version all previous versions are guaranteed to be
		// // unpublished
		// Long lastThoughtVersionId =
		// thought.getRecentUnpublishedVersionIds().get()
		// .getNewest();
		//
		// @SuppressWarnings("unchecked")
		// Draft lastVersion = thoughtVersionDao.get(lastThoughtVersionId);
		// if (lastVersion.getText().equals(text)) {
		// throw new InvalidStateException(
		// "The text did not change from the previous version");
		// }
		//
		// Date now = new Date();
		// thought.setText(text);
		// if (publish) {
		// IdCache recentUnpublishedThoughtIds = thinker
		// .getRecentUnpublishedThoughtIds().get();
		// recentUnpublishedThoughtIds.remove(thought.getId());
		// idCacheDao.put(recentUnpublishedThoughtIds);
		// }
		//
		// Integer lastSequence = thought.getHighestSequence();
		// Long newVersionId = versioner.maintainVersions(text, lastSequence +
		// 1,
		// thought, thinker, publish, now, null, false, false);
		// createVersionAddRecord(thought, newVersionId, thinker.getId(),
		// lastSequence + 1, publish, now);
		// return thought;
	}

	private void createVersionAddRecord(Thought thought, Long thoughtVersionId,
			Long thinkerId, Integer sequence, boolean published, Date dateAdded) {
		VersionAdd thoughtAdded = new VersionAdd(thought.getId(),
				thoughtVersionId, thinkerId, sequence, published, dateAdded);
		versionAddDao.put(thoughtAdded);
	}

	/**
	 * A thinker can publish any yet not published versions of her thoughts. For
	 * a not yet published thought only the last version can be initially
	 * published.
	 * 
	 * @param thinker
	 *            Thinker who is publishing a version of her thought.
	 * @param thoughtVersionId
	 *            Id of the version to publish
	 * @throws InvalidStateException
	 */
	public void publishVersion(Thinker thinker, Thought thought,
			Long thoughtVersionId) throws InvalidStateException {

		// FIXME: add this back in and figure out how to deal with Ref in GWT
		// Draft thoughtVersion = thoughtVersionDao.get(thoughtVersionId);
		// if (!thoughtVersion.getThinkerId().equals(thinker.getId())) {
		// throw new InvalidStateException(
		// "This thought version does not belong to this thinker.");
		// }
		// if (thoughtVersion.isPublished()) {
		// throw new InvalidStateException(
		// "This thought version is already published");
		// }
		//
		// IdCache recentUnpublishedVersionIds = thought
		// .getRecentUnpublishedVersionIds().get();
		// // Not allowing (currently) to publish OLDER versions before the
		// newest
		// // is
		// // published
		// if (!thought.isPublished()
		// && !recentUnpublishedVersionIds.getNewest().equals(
		// thoughtVersion.getId())) {
		// throw new InvalidStateException(
		// "Cannot publish a non-final version of an unpublished thought.");
		// }
		//
		// boolean isOlderThanNewestPublished = thought
		// .getHighestPublishedSequence() != null
		// && thought.getHighestPublishedSequence() > thoughtVersion
		// .getSequence();
		//
		// boolean isTheLatestVersion = thought.getHighestSequence() ==
		// thoughtVersion
		// .getSequence();
		//
		// // Always attempt to remove the version id from the unpublished cache
		// recentUnpublishedVersionIds.remove(thoughtVersion.getId());
		// idCacheDao.put(recentUnpublishedVersionIds);
		//
		// boolean isInitialPublishing = !thought.isPublished();
		// if (isInitialPublishing) {
		// IdCache recentUnpublishedThoughtIds = thinker
		// .getRecentUnpublishedThoughtIds().get();
		// recentUnpublishedThoughtIds.remove(thought.getId());
		// idCacheDao.put(recentUnpublishedThoughtIds);
		// }
		//
		// Date now = new Date();
		//
		// versioner.maintainVersions(null, thoughtVersion.getSequence(),
		// thought,
		// thinker, true, now, thoughtVersion, isOlderThanNewestPublished,
		// isInitialPublishing);
		//
		// VersionPublish versionPublishRecord = new VersionPublish(
		// thinker.getId(), thought.getId(), thoughtVersionId, now,
		// isOlderThanNewestPublished, isTheLatestVersion,
		// isInitialPublishing);
		// versionPublishDao.put(versionPublishRecord);
	}
}
